package com.lekang.system.service.impl;

import com.lekang.system.domain.TaskArrangement;
import com.lekang.system.domain.NursingItemPlanBinding;
import com.lekang.system.domain.OrderManagement;
import com.lekang.system.mapper.CheckInManagementMapper;
import com.lekang.system.mapper.CaregiverBedBindingMapper;
import com.lekang.system.mapper.NursingItemPlanBindingMapper;
import com.lekang.system.mapper.OrderManagementMapper;
import com.lekang.system.service.ITaskArrangementService;
import com.lekang.system.service.ITaskSchedulerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

/**
 * 任务调度服务实现类
 * 负责定时生成和管理护理任务
 */
@Service
public class TaskSchedulerServiceImpl implements ITaskSchedulerService {
    
    private static final Logger log = LoggerFactory.getLogger(TaskSchedulerServiceImpl.class);
    
    @Autowired
    private ITaskArrangementService taskArrangementService;
    
    @Autowired
    private CheckInManagementMapper checkInManagementMapper;
    
    @Autowired
    private CaregiverBedBindingMapper caregiverBedBindingMapper;
    
    @Autowired
    private NursingItemPlanBindingMapper nursingItemPlanBindingMapper;
    
    @Autowired
    private OrderManagementMapper orderManagementMapper;
    
    /**
     * 每日00:00执行 - 生成今日护理任务
     * 根据护理计划、执行周期、执行频次自动生成任务并随机分配护理员
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public Map<String, Object> generateMonthlyTasks() {
        log.info("========== 开始生成今日护理任务 ==========");
        Map<String, Object> result = new HashMap<>();
        result.put("totalTasks", 0);
        result.put("elderlyCount", 0);
        
        try {
            LocalDate today = LocalDate.now();
            int dayOfMonth = today.getDayOfMonth();
            int dayOfWeek = today.getDayOfWeek().getValue(); // 1=Monday, 7=Sunday
            
            // 1. 查询所有在住老人及其护理计划
            List<Map<String, Object>> elderlyList = checkInManagementMapper.selectElderlyWithNursingPlans();
            log.info("找到 {} 个在住老人需要生成任务", elderlyList.size());
            
            if (elderlyList.isEmpty()) {
                log.warn("没有在住老人，跳过任务生成");
                return result;
            }
            
            int totalGenerated = 0;
            int elderlyWithTasks = 0;
            
            // 2. 遍历每个老人
            for (Map<String, Object> elderly : elderlyList) {
                Long elderlyId = getLongValue(elderly.get("elderly_id"));
                Long bedId = getLongValue(elderly.get("bed_id"));
                Long nursingPlanId = getLongValue(elderly.get("nursing_plan_id"));
                String elderlyName = String.valueOf(elderly.get("elderly_name"));
                
                if (nursingPlanId == null) {
                    log.warn("老人ID={} [{}] 未关联护理计划，跳过", elderlyId, elderlyName);
                    continue;
                }
                
                // 3. 获取该床位负责的护理员列表
                List<Long> caregiverIds = caregiverBedBindingMapper.selectCaregiverIdsByBedId(bedId);
                if (caregiverIds == null || caregiverIds.isEmpty()) {
                    log.warn("老人ID={} [{}] 所在床位ID={} 未分配护理员，跳过", elderlyId, elderlyName, bedId);
                    continue;
                }
                
                // 4. 获取护理计划中的所有护理项目
                List<NursingItemPlanBinding> bindings = nursingItemPlanBindingMapper.selectByPlanId(nursingPlanId);
                log.debug("老人ID={} [{}], 护理计划ID={}, 包含 {} 个护理项目", elderlyId, elderlyName, nursingPlanId, bindings.size());
                
                int elderlyTaskCount = 0;
                // 5. 遍历护理项目，根据执行周期判断是否需要生成今日任务
                for (NursingItemPlanBinding binding : bindings) {
                    if (shouldGenerateTask(binding, dayOfMonth, dayOfWeek)) {
                        int generated = generateTasksForBinding(elderlyId, binding, today, caregiverIds);
                        totalGenerated += generated;
                        elderlyTaskCount += generated;
                        log.debug("为老人ID={} [{}] 生成 {} 个任务 (护理项目: {})", 
                            elderlyId, elderlyName, generated, binding.getNursingItemName());
                    }
                }
                
                if (elderlyTaskCount > 0) {
                    elderlyWithTasks++;
                }
            }
            
            result.put("totalTasks", totalGenerated);
            result.put("elderlyCount", elderlyWithTasks);
            log.info("========== 今日护理任务生成完成，共生成 {} 条任务，服务 {} 位老人 ==========", totalGenerated, elderlyWithTasks);
        } catch (Exception e) {
            log.error("生成今日护理任务失败", e);
        }
        
        return result;
    }
    
    /**
     * 判断是否应该生成今日任务
     */
    private boolean shouldGenerateTask(NursingItemPlanBinding binding, int dayOfMonth, int dayOfWeek) {
        Integer executionCycle = binding.getExecutionCycle();
        
        if (executionCycle == null) {
            return false;
        }
        
        // 1=每日, 2=每周, 3=每月
        if (executionCycle == 1) {
            return true; // 每日任务
        } else if (executionCycle == 2) {
            // 每周任务：extraField1存储星期几 "1,3,5" = 周一、周三、周五
            String weekDays = binding.getExtraField1();
            if (weekDays != null && !weekDays.isEmpty()) {
                String[] days = weekDays.split(",");
                for (String day : days) {
                    try {
                        if (Integer.parseInt(day.trim()) == dayOfWeek) {
                            return true;
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析每周执行日期失败: {}", day);
                    }
                }
            }
        } else if (executionCycle == 3) {
            // 每月任务：extraField1存储日期 "1,15" = 每月1号和15号
            String monthDays = binding.getExtraField1();
            if (monthDays != null && !monthDays.isEmpty()) {
                String[] days = monthDays.split(",");
                for (String day : days) {
                    try {
                        if (Integer.parseInt(day.trim()) == dayOfMonth) {
                            return true;
                        }
                    } catch (NumberFormatException e) {
                        log.warn("解析每月执行日期失败: {}", day);
                    }
                }
            }
        }
        
        return false;
    }
    
    /**
     * 为单个护理项目生成多个任务（根据执行频次）并随机分配护理员
     */
    private int generateTasksForBinding(Long elderlyId, NursingItemPlanBinding binding, 
                                        LocalDate today, List<Long> caregiverIds) {
        int generated = 0;
        
        try {
            // ============ 去重检查：避免重复生成 ============
            // 检查今天是否已经为该老人的该护理项目生成过任务
            TaskArrangement checkTask = new TaskArrangement();
            checkTask.setElderlyId(elderlyId);
            checkTask.setProjectNameId(binding.getNursingItemId());
            checkTask.setProjectType("护理计划内");
            checkTask.setStatus("待执行");
            
            List<TaskArrangement> existingTasks = taskArrangementService.selectTaskArrangementList(checkTask);
            
            // 过滤出今天创建的任务
            long todayTaskCount = existingTasks.stream()
                .filter(task -> {
                    if (task.getCreateTime() != null) {
                        java.time.LocalDate createDate = task.getCreateTime().toInstant()
                            .atZone(java.time.ZoneId.systemDefault()).toLocalDate();
                        return createDate.equals(today);
                    }
                    return false;
                })
                .count();
            
            if (todayTaskCount > 0) {
                log.warn("今天已为老人ID={} 的护理项目ID={} 生成过 {} 条任务，跳过重复生成", 
                    elderlyId, binding.getNursingItemId(), todayTaskCount);
                return 0;
            }
            // ============================================
            
            // 执行频次（一天几次）
            int frequency = binding.getExecutionFrequency() != null ? binding.getExecutionFrequency() : 1;
            
            // 基础服务时间
            LocalTime baseTime = binding.getServiceTime() != null ? binding.getServiceTime() : LocalTime.of(9, 0);
            
            // 随机分配：从护理员列表中随机选择
            Random random = new Random();
            
            // 生成多个任务
            for (int i = 0; i < frequency; i++) {
                TaskArrangement task = new TaskArrangement();
                task.setElderlyId(elderlyId);
                task.setProjectNameId(binding.getNursingItemId());
                task.setProjectType("护理计划内");
                
                // 计算服务时间：基础时间 + i*间隔
                LocalDateTime taskTime = LocalDateTime.of(today, baseTime.plusHours(i * 2));
                task.setExpectedServiceTime(java.sql.Timestamp.valueOf(taskTime));
                
                // 随机分配护理员
                Long assignedCaregiver = caregiverIds.get(random.nextInt(caregiverIds.size()));
                task.setExecutor(assignedCaregiver);
                
                task.setStatus("待执行");
                task.setCreateTime(new Date());
                task.setRelatedOrderNo("AUTO-" + today.toString() + "-" + System.currentTimeMillis() + "-" + i);
                
                taskArrangementService.insertTaskArrangement(task);
                generated++;
            }
        } catch (Exception e) {
            log.error("生成任务失败: 老人ID={}, 护理项目ID={}", elderlyId, binding.getNursingItemId(), e);
        }
        
        return generated;
    }
    
    /**
     * 每日00:01执行 - 刷新未执行任务
     * 隐藏已退住老人的任务
     */
    @Scheduled(cron = "0 1 0 * * ?")
    public void refreshDailyTasks() {
        log.info("========== 开始刷新每日未执行任务 ==========");
        try {
            taskArrangementService.refreshUnexecutedTasks();
            log.info("========== 每日未执行任务刷新完成 ==========");
        } catch (Exception e) {
            log.error("刷新每日任务失败", e);
        }
    }
    
    /**
     * 生成入住首月护理任务
     */
    @Override
    public void generateFirstMonthTasks(Long elderlyId, LocalDate checkInDate) {
        log.info("========== 生成入住首月护理任务 ==========");
        log.info("老人ID={}, 入住日期={}", elderlyId, checkInDate);
        try {
            LocalDate firstMonthEnd = checkInDate.plusMonths(1).minusDays(1);
            taskArrangementService.generateFirstMonthInPlanTasks(elderlyId, checkInDate, firstMonthEnd);
            log.info("入住首月护理任务生成完成");
        } catch (Exception e) {
            log.error("生成入住首月任务失败", e);
        }
    }
    
    /**
     * 生成护理计划外任务
     */
    @Override
    public void generateOutOfPlanTasks(Long orderId, Long elderlyId, Long nursingItemId, 
                                      LocalDateTime serviceTime, String orderNo) {
        log.info("========== 生成护理计划外任务 ==========");
        log.info("订单ID={}, 老人ID={}, 护理项目ID={}, 服务时间={}, 订单号={}", 
            orderId, elderlyId, nursingItemId, serviceTime, orderNo);
        try {
            taskArrangementService.generateOutOfPlanTask(elderlyId, nursingItemId, serviceTime, orderNo);
            log.info("护理计划外任务生成完成");
        } catch (Exception e) {
            log.error("生成护理计划外任务失败", e);
        }
    }
    
    /**
     * 生成护理计划外任务（从订单生成）
     * 每10分钟执行一次，检查已支付但未生成任务的订单
     */
    @Scheduled(cron = "0 */10 * * * ?")
    public void generateTasksFromPaidOrders() {
        log.info("========== 开始生成护理计划外任务（从订单） ==========");
        
        try {
            // 查询已支付但未生成任务的订单
            List<OrderManagement> paidOrders = orderManagementMapper.selectPaidOrdersWithoutTask();
            
            if (paidOrders == null || paidOrders.isEmpty()) {
                log.info("没有需要生成任务的已支付订单");
                return;
            }
            
            log.info("找到{}笔已支付订单需要生成任务", paidOrders.size());
            
            int successCount = 0;
            int failCount = 0;
            
            for (OrderManagement order : paidOrders) {
                try {
                    // 1. 根据老人床位查询绑定的护理员
                    List<Map<String, Object>> caregivers = caregiverBedBindingMapper.selectCaregiversByElderlyId(order.getElderlyId());
                    Long assignedCaregiver = null;
                    
                    if (caregivers != null && !caregivers.isEmpty()) {
                        // 随机分配一个护理员
                        int randomIndex = new Random().nextInt(caregivers.size());
                        Object caregiverId = caregivers.get(randomIndex).get("caregiver_id");
                        assignedCaregiver = getLongValue(caregiverId);
                        log.info("为老人ID:{} 分配护理员ID:{}", order.getElderlyId(), assignedCaregiver);
                    } else {
                        log.warn("老人ID:{} 没有绑定护理员,任务将不分配执行人", order.getElderlyId());
                    }
                    
                    // 2. 创建护理计划外任务
                    TaskArrangement task = new TaskArrangement();
                    task.setElderlyId(order.getElderlyId());
                    task.setProjectNameId(order.getNursingItemId());
                    task.setProjectType("护理计划外"); // 标记为护理计划外
                    task.setExpectedServiceTime(order.getExpectedServiceTime());
                    task.setStatus("待执行");
                    task.setCreateTime(new Date());
                    task.setRelatedOrderNo(order.getOrderNo()); // 关联订单号
                    task.setExecutor(assignedCaregiver); // 分配护理员
                    
                    // 保存任务
                    taskArrangementService.insertTaskArrangement(task);
                    
                    successCount++;
                    log.info("成功生成护理计划外任务 - 订单号:{}, 老人ID:{}, 护理项目ID:{}, 服务时间:{}, 执行人:{}", 
                        order.getOrderNo(), 
                        order.getElderlyId(), 
                        order.getNursingItemId(),
                        order.getExpectedServiceTime(),
                        assignedCaregiver != null ? assignedCaregiver : "未分配");
                    
                } catch (Exception e) {
                    failCount++;
                    log.error("生成护理计划外任务失败 - 订单号:{}, 错误:{}", 
                        order.getOrderNo(), e.getMessage(), e);
                }
            }
            
            log.info("========== 护理计划外任务生成完成 - 成功:{}, 失败:{} ==========", successCount, failCount);
            
        } catch (Exception e) {
            log.error("生成护理计划外任务过程出错", e);
        }
    }
    
    /**
     * 生成测试任务（手动触发）
     */
    @Override
    public void generateTestTasks() {
        log.info("========== 开始生成测试任务 ==========");
        try {
            LocalDate today = LocalDate.now();
            
            // 创建今天不同时间点的测试任务
            for (int i = 0; i < 6; i++) {
                TaskArrangement task = new TaskArrangement();
                task.setElderlyId((long) (i % 3 + 1)); // 老人ID 1-3循环
                task.setProjectNameId((long) (i % 4 + 1)); // 护理项目ID 1-4循环
                task.setProjectType("护理计划内");
                
                // 今天的不同时间: 8:00, 10:00, 12:00, 14:00, 16:00, 18:00
                LocalDateTime taskTime = LocalDateTime.of(today, LocalTime.of(8 + i * 2, 0));
                task.setExpectedServiceTime(java.sql.Timestamp.valueOf(taskTime));
                
                task.setStatus("待执行");
                task.setCreateTime(new Date());
                task.setRelatedOrderNo("TEST-" + System.currentTimeMillis() + "-" + i);
                
                taskArrangementService.insertTaskArrangement(task);
            }
            
            log.info("========== 测试任务生成完成，共生成6条今日任务 ==========");
        } catch (Exception e) {
            log.error("生成测试任务失败", e);
            throw e;
        }
    }
    
    /**
     * 安全地将Object转换为Long
     */
    private Long getLongValue(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Long) {
            return (Long) value;
        }
        if (value instanceof Integer) {
            return ((Integer) value).longValue();
        }
        try {
            return Long.parseLong(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
}
